package com.geezdata.cps.base.utils;

import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

public class ProxyUtil {
    private static Logger logger = LoggerFactory.getLogger(ProxyUtil.class);

    /**
     * 获取代理Bean的原始Bean
     *
     * @param bean
     * @return
     */
    @SuppressWarnings("unchecked")
	public static final <T> T unwrapProxy(Object bean) throws Exception {
        if (AopUtils.isAopProxy(bean) && bean instanceof Advised) {
            Advised advised = (Advised) bean;
            bean = advised.getTargetSource().getTarget();
        }

        return (T) bean;
    }

    public static boolean isProxy(Object obj) {
        return AopUtils.isAopProxy(obj) || obj instanceof Advised || isCglibProxy(obj) || isJdkDynamicProxy(obj);
    }

    public static Object getCglibProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);

        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();

        return target;
    }

    public static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);

        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();

        return target;
    }

    private static boolean isCglibProxy(Object obj) {
        try {
            Field field = obj.getClass().getDeclaredField("CGLIB$CALLBACK_0");

            return field != null;
        } catch (Exception e) {
            logger.debug(e.getMessage(), e);
        }

        return false;
    }

    private static boolean isJdkDynamicProxy(Object obj) {
        try {
            Field field = obj.getClass().getSuperclass().getDeclaredField("h");

            return field != null;
        } catch (Exception e) {
            logger.debug(e.getMessage(), e);
        }

        return false;
    }
}
